#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "pwm/timer_pwm.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "inc/hw_timer.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "utils/uartstdio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "key.h"
#include "lcd.h"
#include "num_str.h"
void Init_PWM(void);
void pwm_adjust(void);
void pwm_freq(void);
void pwm_duty_cycle(void);
void Init_timer(void);
void Time(void);

ModPwm modPwm = {
    .freq = 50,
    .duty_cycle = 50.0f,
    .key_pwm = EMPTY_INPUT,
    .isrunning = false,
    .pwmInit = Init_PWM,
    .pwmAdjust = pwm_adjust,
    .pwmFreq = pwm_freq,
    .pwmDutyCycle = pwm_duty_cycle,
};

ModTimer modTimer = {
    .timerInit = Init_timer,
    .timeStamp = Time,
};


void Init_PWM()
{

	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);
    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    
    GPIOPinConfigure(GPIO_PC7_WT1CCP1);

    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_7);
  
    TimerConfigure(WTIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM); 

    TimerLoadSet(WTIMER1_BASE, TIMER_B, ROM_SysCtlClockGet()/modPwm.freq);

    TimerMatchSet(WTIMER1_BASE, TIMER_B, TimerLoadGet(WTIMER1_BASE, TIMER_B)*(100.0f-modPwm.duty_cycle)/100);
 
    TimerEnable(WTIMER1_BASE, TIMER_B);
    
    modPwm.isrunning = true;
}
  

void pwm_adjust() {
    Init_PWM();
    uint8_t key = EMPTY_INPUT;
    TFT_Clear(BLACK);
    TFT_String(5,5,WHITE,BLACK,"1.freq");
    TFT_String(5,25,WHITE,BLACK,"2.duty cycle");
    while(1) {
        if(modPwm.key_pwm == KEY_BACK||modPwm.key_pwm == KEY_ENTER){
            TFT_Clear(BLACK);
            TFT_String(5,5,WHITE,BLACK,"1.freq");
            TFT_String(5,25,WHITE,BLACK,"2.duty cycle");
            modPwm.key_pwm = EMPTY_INPUT;
        }
        key=check_key();
        switch(key) {
            case 1:pwm_freq();
                break;
            case 2:pwm_duty_cycle();
                break;
            case KEY_BACK:
                return;
        }                 
    }
}

void pwm_freq() {

    unsigned char s[10];
    TFT_Clear(BLACK);
    TFT_String(5,5,WHITE, BLACK,"old:");
    uint322str(modPwm.freq,modPwm.str);
    TFT_String(35,5,WHITE,BLACK, modPwm.str);
    TFT_String(5,25,WHITE,BLACK, "new:");
    input_string(35,25, s);
    if(modPwm.key_pwm == KEY_BACK)
        return;
    str2int32(&modPwm.freq, s);
    TimerLoadSet(WTIMER1_BASE, TIMER_B, ROM_SysCtlClockGet() / modPwm.freq);
    TimerMatchSet(WTIMER1_BASE, TIMER_B, (100.0f - modPwm.duty_cycle) / 100 * TimerLoadGet(WTIMER1_BASE, TIMER_B));
    if(modPwm.key_pwm == KEY_ENTER)
        return;
}
void pwm_duty_cycle() {
    unsigned char s[10];
    TFT_Clear(BLACK);
    TFT_String(5, 5, WHITE, BLACK, "old:");
    uint322str((uint32_t) modPwm.duty_cycle, modPwm.str);
    TFT_String(35, 5, WHITE, BLACK, modPwm.str);
    TFT_String(5,25, WHITE,BLACK, "new:");
    input_string(35,25, s);
    if(modPwm.key_pwm == KEY_BACK)
        return;
    str2float(&modPwm.duty_cycle, s);
    TimerMatchSet(WTIMER1_BASE, TIMER_B, (100.0f - modPwm.duty_cycle) / 100 * TimerLoadGet(WTIMER1_BASE, TIMER_B));
    if(modPwm.key_pwm == KEY_ENTER)
        return;
}

void Init_timer() {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);
    TimerLoadSet(TIMER0_BASE,TIMER_B,0x9C40);
    IntMasterEnable();
    TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
    IntEnable(INT_TIMER0B);
    TimerEnable(TIMER0_BASE, TIMER_B);
}

void Timer0BIntHandler() {
    TimerIntClear(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
    modTimer.ui32Counter++;
    if (modTimer.ui32Counter == 0xFFFFFFFF)
        modTimer.ui32Counter = 0;
}

void Time() {
    uint8_t key = EMPTY_INPUT;
    char time_str[100];
    TFT_Clear(BLACK);
    TFT_String(5, 5, WHITE, BLACK, "Time(s):");
    while(key != KEY_BACK)
    {   
        key = check_key();
        sprintf(time_str, "%ld", modTimer.ui32Counter / 1000l);
        TFT_String(100, 5, WHITE, BLACK, time_str);
    }
}
